/**
 * PHOSIDE: PHosphorylation Site IDentification Engine.
 * Copyright 2009 Digital Biology Lab, University of Missouri.
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version. <p/> This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more
 * details.
 */

package phoside.miscellaneous.io;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import phoside.PhosphoProteins;
import phoside.PhosphoProteinsImpl;
import phoside.Protein;

import phoside.io.ProteinsReader;
import phoside.io.fasta.FastaProteinsReaderFromFile;
import phoside.io.fasta.parser.DefaultHeaderRule;
import phoside.io.xml.PhosideXmlProteinsReader;
import phoside.io.xml.PhosideXmlProteinsWriter;
import phoside.io.xml.PhosphoProteinFieldValueFormatter;
import phoside.io.xml.UniProtPhosphoReader;

import phoside.util.IOUtil;

/**
 *
 * @author gjj
 */
public class PhosphoReaderPhosphoPep implements ProteinsReader {
    private PhosphoProteins data;
    private String dir;
    private IncludeAmbiguous amb;
    private Map<String,String> idmap;

    public enum IncludeAmbiguous {
        AMBIGUOUS, NONAMBIGOUS, BOTH;
    }

    public PhosphoReaderPhosphoPep(PhosphoProteins data, String dir,
            IncludeAmbiguous amb, Map<String,String> idmap) {
        this.data = data;
        this.dir = dir;
        this.amb = amb;
        this.idmap = idmap;
    }

    public PhosphoProteins read() throws IOException {
        Map<String,Set<String>> mapAccPeps = readPeptide(dir);
        for (Map.Entry<String,Set<String>> entry : mapAccPeps.entrySet()) {
            String acc = entry.getKey();
            if (acc==null||acc.length()==0)
                continue;
            
            if (idmap!=null)
                acc = idmap.get(acc);

            if (acc==null)
                continue;

            Set<String> peps = entry.getValue();
            Protein protein = data.getProtein(acc);
            if (protein==null) {
                System.err.println(acc+" does not exist.");
                continue;
            }

            Set<Integer> sites = readSites(protein, peps);
            data.addSites(acc, sites);
        }
        return data;
    }

    private Set<Integer> readSites(Protein protein, Set<String> peps) throws IOException {
        Set<Integer>  sites = new HashSet();

        String proSeq = protein.getSequence();

        for (String pep : peps) {
            if (amb==IncludeAmbiguous.AMBIGUOUS) {
                pep = pep.replaceAll("p", "");
            } else if (amb==IncludeAmbiguous.NONAMBIGOUS) {
                pep = pep.replaceAll("a", "");
            }

            int s = pep.indexOf('.');
            int t = pep.indexOf('.',s+1);
            pep = pep.substring(s+1,t);

            pep = pep.replaceAll("[ap](.)", "$1#");
            pep = pep.toUpperCase();

            int pepLoc = proSeq.indexOf(pep.replaceAll("#", ""));
            if (pepLoc==-1) {
                System.err.println("peptide not exist: "+protein.getAccession()+": "+pep);
                continue;
            }

            int idx = pep.indexOf('#');
            while (idx>-1) {
                sites.add(pepLoc+idx-1);
                pep = pep.substring(0,idx)+pep.substring(idx+1);
                idx = pep.indexOf('#', idx);
            }
        }

        return sites;
    }

    private Map<String,Set<String>> readPeptide(String localFile) throws IOException {
        Map<String,Set<String>> map = new HashMap();
        List<String> lines = IOUtil.readStringListAscii(localFile);
        String acc = null;
        Set<String> peps = null;
        for (String line : lines) {
            if (line.startsWith(">")) {
                String[] strs = line.split("\t");
                acc = strs[0].substring(1);
                peps = map.get(acc);
                if (peps==null) {
                    peps = new HashSet();
                    map.put(acc, peps);
                }
            } else {
                String[] strs = line.split("\t");
                peps.add(strs[0]);
            }
        }
        
        return map;
    }

    

    public static void main(String[] args) {
        PhosphoProteins phosphoData = new PhosphoProteinsImpl();

//        String fasta = "D:\\projects\\PHOSIDE\\PHOSIDE\\data\\processing\\dmel-all-translation-r5.21.fasta";
//        //String accRegEx = "([^ ]+) ";
//        String accRegEx = "parent=(FBgn[0-9]+)";
//        DefaultHeaderRule headerRule = new DefaultHeaderRule(accRegEx);

//        String xml = "D:\\projects\\PHOSIDE\\PHOSIDE\\data\\phosphopep\\PhosphoPep-fly-10022009_uniprot.phoside.xml";
//        PhosideXmlProteinsReader phosphoReader = new PhosideXmlProteinsReader(xml, phosphoData, new PhosphoProteinFieldValueFormatter(), null);

        String xml = "D:\\projects\\PHOSIDE\\PHOSIDE\\data\\phosphopep\\PhosphoPep-worm-10022009.uniprot.xml";
        UniProtPhosphoReader phosphoReader = new UniProtPhosphoReader(xml,phosphoData);
        phosphoReader.setKeepAllIds();

        String dirPep = "D:\\projects\\PHOSIDE\\PHOSIDE\\data\\phosphopep\\PhosphoPep-worm-10022009_uniprot.pep";
        

        String dirOut = "D:\\projects\\PHOSIDE\\PHOSIDE\\data\\phosphopep\\PhosphoPep-worm-10022009.phoside.xml";
        PhosideXmlProteinsWriter writer = new PhosideXmlProteinsWriter(dirOut, new PhosphoProteinFieldValueFormatter());
        

        try {
//            FastaProteinsReaderFromFile phosphoReader = new FastaProteinsReaderFromFile(fasta,phosphoData,headerRule);
            phosphoReader.read();

            java.util.Iterator<Protein> it = phosphoData.proteinIterator();
            while (it.hasNext()) {
                phosphoData.clearSites(it.next().getAccession());
            }

            PhosphoReaderPhosphoPep pep = new PhosphoReaderPhosphoPep(phosphoData, dirPep,
                IncludeAmbiguous.NONAMBIGOUS, phosphoReader.getIDMap());

            pep.read();

            writer.write(phosphoData);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }



}
